#include "oled.h"

/*
    x 从0开始，每+1表示一个像素，每个全角字符号占16像素，每个半角字符8像素
    y 从0开始，每+1表示半个字高，+2表示一个字高
*/

#ifndef OLED_USE_SPI
const GPIO_Init_Param_Typedef GPIO_OLED[5] =
    {
        {GPIOA, {LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT, LL_GPIO_SPEED_FREQ_HIGH, LL_GPIO_OUTPUT_PUSHPULL, 0}, 1}, // CLK
        {GPIOA, {LL_GPIO_PIN_7, LL_GPIO_MODE_OUTPUT, LL_GPIO_SPEED_FREQ_HIGH, LL_GPIO_OUTPUT_PUSHPULL, 0}, 0}, // MOSI
        {GPIOB, {LL_GPIO_PIN_0, LL_GPIO_MODE_OUTPUT, LL_GPIO_SPEED_FREQ_HIGH, LL_GPIO_OUTPUT_PUSHPULL, 0}, 0}, // DC
        {GPIOB, {LL_GPIO_PIN_1, LL_GPIO_MODE_OUTPUT, LL_GPIO_SPEED_FREQ_HIGH, LL_GPIO_OUTPUT_PUSHPULL, 0}, 1}, // OLED_CS
        {0, {0, 0, 0, 0, 0}, 0}};
#else
const GPIO_Init_Param_Typedef GPIO_OLED[3] =
    {
        {GPIOB, {LL_GPIO_PIN_0, LL_GPIO_MODE_OUTPUT, LL_GPIO_SPEED_FREQ_HIGH, LL_GPIO_OUTPUT_PUSHPULL, 0}, 0}, // Data or Cmd
        {GPIOB, {LL_GPIO_PIN_1, LL_GPIO_MODE_OUTPUT, LL_GPIO_SPEED_FREQ_HIGH, LL_GPIO_OUTPUT_PUSHPULL, 0}, 1}, // OLED_CS
        {0, {0, 0, 0, 0, 0}, 0}};
#endif // !OLED_USE_SPI

uint8_t display_row = 0;

#ifndef OLED_USE_SPI
void oled_byte_write(uint8_t cmd)
{
    for (uint8_t clk = 0; clk < 8; clk++)
    {
        OLED_CLK = 0;
        OLED_MOSI = cmd & 0x80 ? 1 : 0;
        OLED_CLK = 1;
        cmd <<= 1;
    }
}

void oled_write(uint8_t *cmd, uint8_t n)
{
    while (n--)
    {
        /* 用注释掉和程序死活不行,操!!!!! */
        // for (uint8_t clk = 0; clk < 8; clk++)
        // {
        //     OLED_CLK = 0;
        //     OLED_MOSI = *cmd & 0x80 ? 1 : 0;
        //     OLED_CLK = 1;
        //     *cmd <<= 1;
        // }
        oled_byte_write(*cmd);
        cmd++;
    }
}
#endif // !USE_SPI

// LCD模块初始化
void oled_init()
{
    const uint8_t cmd[28] = {0xAE, 0x20, 0x10, 0xb0, 0xc8, 0x00, 0x10, 0x40, 0x81, 0xFF,
                             0xa1, 0xa6, 0xa8, 0x3F, 0xa4, 0xd3, 0x00, 0xd5, 0xf0, 0xd9,
                             0x22, 0xda, 0x12, 0xdb, 0x20, 0x8d, 0x14, 0xaf};
    GPIO_Init((GPIO_Init_Param_Typedef *)GPIO_OLED);
    OLED_CS = 0;
    CMD0_DATA1 = 0;
    oled_write((uint8_t *)cmd, 28);
    OLED_CS = 1;
    oled_clear();
}

// 设置要写的显存地址
void oled_set_addr(uint8_t page, uint8_t column)
{
    CMD0_DATA1 = 0;
    oled_byte_write(0xB0 + page);          // 设置页地址
    oled_byte_write((column >> 4) | 0x10); // 设置列地址的高4位
    oled_byte_write(column & 0x0F);        // 设置列地址的低4位
}

// 清屏
void oled_clear()
{
    OLED_CS = 0;
    for (uint8_t i = 0; i < 8; i++)
    {
        oled_set_addr(i, 0);
        CMD0_DATA1 = 1;
        for (uint8_t page = 0; page < 128; page++)
        {
            oled_byte_write(0x00);
        }
    }
    OLED_CS = 1;
}

// 显示128x64点阵图像
void oled_display_128x64(uint8_t *dp)
{
    OLED_CS = 0;
    for (uint8_t page = 0; page < 8; page++)
    {
        oled_set_addr(page, 0);
        CMD0_DATA1 = 1;
        oled_write(dp, 128);
        dp += 128;
    }
    OLED_CS = 1;
}

// 显示24x24点阵图像、汉字、生僻字或24x24点阵的其他图标
void oled_display_24x24(uint16_t page, uint16_t column, uint8_t *dp)
{
    OLED_CS = 0;

    oled_set_addr(page, column);
    CMD0_DATA1 = 1;
    oled_write(dp, 24);

    oled_set_addr(page + 1, column);
    CMD0_DATA1 = 1;
    oled_write(dp + 24, 24);

    oled_set_addr(page + 2, column);
    CMD0_DATA1 = 1;
    oled_write(dp + 48, 24);

    OLED_CS = 1;
}
// 显示16x16点阵图像、汉字、生僻字或16x16点阵的其他图标
void oled_display_16x16(uint16_t page, uint16_t column, uint8_t *dp)
{
    OLED_CS = 0;
    oled_set_addr(page, column);
    CMD0_DATA1 = 1;
    oled_write(dp, 16);
    oled_set_addr(page + 1, column);
    CMD0_DATA1 = 1;
    oled_write(dp + 16, 16);
    OLED_CS = 1;
}

// 显示8x16点阵图像、ASCII, 或8x16点阵的自造字符、其他图标
void oled_display_8x16(uint16_t page, uint8_t column, uint8_t *dp)
{
    OLED_CS = 0;
    oled_set_addr(page, column);
    CMD0_DATA1 = 1;
    oled_write(dp, 8);
    oled_set_addr(page + 1, column);
    CMD0_DATA1 = 1;
    oled_write(dp + 8, 8);
    OLED_CS = 1;
}

// 显示5*7点阵图像、ASCII, 或5x7点阵的自造字符、其他图标
void oled_display_5x7(uint16_t page, uint8_t column, uint8_t *dp)
{
    OLED_CS = 0;
    oled_set_addr(page, column);
    CMD0_DATA1 = 1;
    oled_write(dp, 8);
    OLED_CS = 1;
}

// 显示高度为16的汉字和ASCII字符串
void oled_print_h16_string(uint8_t y, uint8_t x, uint8_t *text)
{
    uint8_t i = 0;
    uint8_t fontbuf[33];
    while ((text[i] > 0x00))
    {
        /* ASCII */
        if ((text[i] >= 0x20) && (text[i] <= 0x7F))
        {
            oled_display_8x16(y, x, zk_get_8x16_font(text[i]));
            i += 1;
            x += 8;
        }
        /* 全角字符 */
        else
        {
            ZK_CS = 0;
            zk_set_16x16_address(*(uint16_t *)&text[i]);
            zk_read(fontbuf, 32);
            ZK_CS = 1;
            oled_display_16x16(y, x, fontbuf);
            i += 2;
            x += 16;
        }
    }
}

// 显示半角 5*7 的字符串
void oled_print_h7_string(uint8_t y, uint8_t x, uint8_t *text)
{
    uint8_t i = 0;
    while (text[i])
    {
        if ((text[i] >= 0x20) && (text[i] <= 0x7e))
        {
            oled_display_5x7(y, x, zk_get_5x7_font(text[i]));
            i += 1;
            x += 6;
        }
        else
        {
            i++;
        }
    }
}

/*简单打印一个十进制数*/
void oled_print_uint16(uint8_t y, uint8_t x, uint16_t n, uint8_t fullOrHalf)
{
    uint8_t str[6];
    str[5] = 0;
    str[4] = (n / 1) % 10 + '0';
    str[3] = (n / 10) % 10 + '0';
    str[2] = (n / 100) % 10 + '0';
    str[1] = (n / 1000) % 10 + '0';
    str[0] = (n / 10000) % 10 + '0';

    if (fullOrHalf == OLED_FULL)
    {
        oled_print_h16_string(y, x, str);
    }
    else
    {
        oled_print_h7_string(y, x, str);
    }
}

/*打印一个十六进制数*/
void oled_print_hex8(uint8_t y, uint8_t x, uint8_t n, uint8_t fullOrHalf)
{
    const uint8_t tab[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    if (fullOrHalf == OLED_FULL)
    {
        oled_display_8x16(y, x, zk_get_8x16_font(tab[n >> 4]));
        oled_display_8x16(y, x + 8, zk_get_8x16_font(tab[n & 0x0F]));
    }
    else
    {
        oled_display_5x7(y, x, zk_get_5x7_font(tab[n >> 4]));
        oled_display_5x7(y, x + 6, zk_get_5x7_font(tab[n & 0x0F]));
    }
}

/*打印一个十六进制数*/
void oled_print_hex16(uint8_t y, uint8_t x, uint16_t n, uint8_t fullOrHalf)
{
    oled_print_hex8(y, x, n >> 8, fullOrHalf);
    oled_print_hex8(y, x + 16, n, fullOrHalf);
}

void oled_zk_test()
{
    while (1)
    {
        uint8_t font[32] = {0};
        uint8_t r = 0, c = 16 * 2;
        for (uint16_t row = 0xA1; row < 0xA1 + 87 - 1; row++)
        {
            for (uint16_t pos = 0xA1; pos <= 0xFE; pos++)
            {
                /* 打印区码 */
                oled_print_hex8(0, 8, (uint8_t)row, OLED_FULL);
                if (((row >= 0xA4) && (row <= 0xA8)) || ((row > 0xA9) && (row <= 0xAF)))
                {
                    r = 0;
                    c = 16 * 2;
                    break;
                }
                /* 读字并打印 */
                ZK_CS = 0;
                zk_set_16x16_address(row | pos << 8);
                zk_read(font, 32);
                ZK_CS = 1;
                oled_display_16x16(r, c, font);
                /* 更改打印位置 */
                c += 16;
                /* 分页打印 */
                if (c == 128)
                {
                    r += 2;
                    if (r == 8)
                    {
                        r = 0;
                        c = 16 * 2;
                        LL_mDelay(500);
                    }
                    else
                    {
                        c = 0;
                    }
                }
            }
        }
    }
}